package views;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Scanner;

import model.EnhancedCostEvaluator;
import model.Problem;
import model.Solution;
import model.SolverEnvironment;
import solver.CollaboratingSolvers;
import solver.LateAcceptanceHeuristicSolver;
import util.Chronograph;
import util.Importer;
import util.SolutionImporter;

public class ScoreApp {

	public static void main(String[] args) {
		System.out.println("Phase A score");
		Scanner in = new Scanner(System.in);
		System.out.println("1. Qualification phase");
		System.out.println("2. Final phase");
		int choice = in.nextInt();
		ScoreApp app;
		if (choice == 1) {
			app = new ScoreApp(1);
		} else {
			app = new ScoreApp(2);
		}
		List<Integer> selected_datasets = app.selectDatasets();
		System.out.print("How much time for each run: ");
		int time_limit = in.nextInt();
		System.out.println("1. Late acceptance solver");
		System.out.println("2. IP solver Gurobi");
		System.out.println("3. IP solver ORTools-CBC");
		System.out.println("4. All");
		System.out.print("Enter choice: ");
		choice = in.nextInt();
		System.out.print("Enter a comment (to be included in the output): ");
		Scanner in2 = new Scanner(System.in);
		Calendar cal = Calendar.getInstance();
		cal.getTime();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		app.comment = in2.nextLine();
		if (!app.comment.equalsIgnoreCase(""))
			app.openAndAppendData(sdf.format(cal.getTime()) + " " + app.comment
					+ "\n");
		else
			app.openAndAppendData(sdf.format(cal.getTime()) + "\n");
		if (choice == 1) {
			app.lahc_batch_run(selected_datasets, time_limit);
		} else if (choice == 2) {
			app.ipsolver_batch_run(selected_datasets, time_limit, true);
		} else if (choice == 3) {
			app.ipsolver_batch_run(selected_datasets, time_limit, false);

		} else {
			app.lahc_batch_run(selected_datasets, time_limit);
			app.ipsolver_batch_run(selected_datasets, time_limit, true); // Gurobi
			app.ipsolver_batch_run(selected_datasets, time_limit, false); // ORTools
		}
		System.out.println("Run completed. The output is in " + app.fileName);
		System.exit(0);
	}

	String[] datasets = new String[10];
	String[] initial_solutions = new String[10];
	long[] best_solutions = new long[10];
	String fileName;
	String comment = "";

	public ScoreApp(int phase) {
		if (phase == 1) {
			qualificationPhase();
		} else if (phase == 2) {
			finalPhase();
		}
	}

	public void qualificationPhase() {
		datasets[0] = "datasets//model_a1_1.txt";
		datasets[1] = "datasets//model_a1_2.txt";
		datasets[2] = "datasets//model_a1_3.txt";
		datasets[3] = "datasets//model_a1_4.txt";
		datasets[4] = "datasets//model_a1_5.txt";
		datasets[5] = "datasets//model_a2_1.txt";
		datasets[6] = "datasets//model_a2_2.txt";
		datasets[7] = "datasets//model_a2_3.txt";
		datasets[8] = "datasets//model_a2_4.txt";
		datasets[9] = "datasets//model_a2_5.txt";
		initial_solutions[0] = "solutions//assignment_a1_1.txt";
		initial_solutions[1] = "solutions//assignment_a1_2.txt";
		initial_solutions[2] = "solutions//assignment_a1_3.txt";
		initial_solutions[3] = "solutions//assignment_a1_4.txt";
		initial_solutions[4] = "solutions//assignment_a1_5.txt";
		initial_solutions[5] = "solutions//assignment_a2_1.txt";
		initial_solutions[6] = "solutions//assignment_a2_2.txt";
		initial_solutions[7] = "solutions//assignment_a2_3.txt";
		initial_solutions[8] = "solutions//assignment_a2_4.txt";
		initial_solutions[9] = "solutions//assignment_a2_5.txt";
		best_solutions[0] = 44306501L;
		best_solutions[1] = 777532896L;
		best_solutions[2] = 583005717L;
		best_solutions[3] = 252728589L;
		best_solutions[4] = 727578309L;
		best_solutions[5] = 198L;
		best_solutions[6] = 816523983L;
		best_solutions[7] = 1306868761L;
		best_solutions[8] = 1681353943L;
		best_solutions[9] = 336170182L;
		Calendar cal = Calendar.getInstance();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
		fileName = String.format("batch_run_results_a_%s.txt",
				sdf.format(cal.getTime()));
	}

	public void finalPhase() {
		datasets[0] = "datasets//model_b_1.txt";
		datasets[1] = "datasets//model_b_2.txt";
		datasets[2] = "datasets//model_b_3.txt";
		datasets[3] = "datasets//model_b_4.txt";
		datasets[4] = "datasets//model_b_5.txt";
		datasets[5] = "datasets//model_b_6.txt";
		datasets[6] = "datasets//model_b_7.txt";
		datasets[7] = "datasets//model_b_8.txt";
		datasets[8] = "datasets//model_b_9.txt";
		datasets[9] = "datasets//model_b_10.txt";
		initial_solutions[0] = "solutions//assignment_b_1.txt";
		initial_solutions[1] = "solutions//assignment_b_2.txt";
		initial_solutions[2] = "solutions//assignment_b_3.txt";
		initial_solutions[3] = "solutions//assignment_b_4.txt";
		initial_solutions[4] = "solutions//assignment_b_5.txt";
		initial_solutions[5] = "solutions//assignment_b_6.txt";
		initial_solutions[6] = "solutions//assignment_b_7.txt";
		initial_solutions[7] = "solutions//assignment_b_8.txt";
		initial_solutions[8] = "solutions//assignment_b_9.txt";
		initial_solutions[9] = "solutions//assignment_b_10.txt";
		best_solutions[0] = 3290754940L;
		best_solutions[1] = 1015153860L;
		best_solutions[2] = 156631070L;
		best_solutions[3] = 4677767120L;
		best_solutions[4] = 922858550L;
		best_solutions[5] = 9525841820L;
		best_solutions[6] = 14833996360L;
		best_solutions[7] = 1214153440L;
		best_solutions[8] = 15885369400L;
		best_solutions[9] = 18048006980L;
		Calendar cal = Calendar.getInstance();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
		fileName = String.format("batch_run_results_b_%s.txt",
				sdf.format(cal.getTime()));
	}

	public void lahc_batch_run(List<Integer> selected_datasets, int time_limit) {
		openAndAppendData(String.format("LAHC %d seconds\n", time_limit));
		double sum = 0.0;
		// Problem.RANDOM_SEED = 1L;
		Problem.RANDOM_SEED = 123456789L;
		for (Integer i : selected_datasets) {
			Chronograph chronos = new Chronograph();
			chronos.reset();
			Importer importer = new Importer(datasets[i]);
			importer.readData();
			Problem problem = importer.getProblem();
			SolutionImporter solutionImporter = new SolutionImporter(problem);
			solutionImporter.setSolutionFileName(initial_solutions[i]);
			Solution solution1 = solutionImporter.readData();
			Problem.VERBOSE = false;
			// LateAcceptanceHeuristicSolver solver = new
			// LateAcceptanceHeuristicSolver(
			// problem, solution1);
			CollaboratingSolvers solver = new CollaboratingSolvers(problem,
					solution1);
			chronos.lap();
			int passed_time = chronos.getElapsedTimeInSeconds();
			int usedTime = solver.solveWithTimeLimit(time_limit - passed_time);

			SolverEnvironment env = new SolverEnvironment(problem, solution1,
					solver.getNewSolution());
			EnhancedCostEvaluator ece = env.getFullValidator();
			ece.computeCost();
			long overall_cost_i = env.getFullValidator().getNewSolutionCost();
			long overall_cost_r = env.getFullValidator()
					.getInitialSolutionCost();
			long overall_cost_b = best_solutions[i];
			double score = (overall_cost_i - overall_cost_b)
					/ (double) overall_cost_r;

			openAndAppendData(String
					.format("%s INITIAL_SOLUTION_COST=%,d NEW_COST=%,d BEST_COST=%,d ==> %.4f\n",
							datasets[i], overall_cost_r, overall_cost_i,
							overall_cost_b, score * 100));
			sum += score;
		}
		openAndAppendData(String.format("The cost is %.4f\n", sum * 100));
	}

	public List<Integer> selectDatasets() {
		List<Integer> selected_datasets = new ArrayList<Integer>();
		Scanner in = new Scanner(System.in);
		int pos = -1;
		for (int i = 0; i < 10; i++) {
			System.out.printf("Include %s (Y/N/A)", datasets[i]);
			String ans = in.next();
			if (ans.equalsIgnoreCase("y"))
				selected_datasets.add(i);
			else if (ans.equalsIgnoreCase("a")) {
				pos = i;
				break;
			}
		}
		if (pos != -1) {
			for (int i = pos; i < 10; i++) {
				System.out.printf("Dataset %s included\n", datasets[i]);
				selected_datasets.add(i);
			}
		}
		return selected_datasets;
	}

	public void ipsolver_batch_run(List<Integer> selected_datasets,
			int time_limit, boolean useGRB) {
		if (useGRB)
			openAndAppendData(String.format("GUROBI %d seconds\n", time_limit));
		else
			openAndAppendData(String.format("ORTOOLS + CBC %d seconds\n",
					time_limit));
		double sum = 0.0;

		for (Integer i : selected_datasets) {
			MachineReassignmentMay2012 mare2 = new MachineReassignmentMay2012();
			mare2.setUseGRB(useGRB);
			mare2.launch(time_limit, datasets[i], initial_solutions[i],
					"output", 1821L);
			SolverEnvironment env = mare2.getSolverEnvironment();
			env.getFullValidator().computeCost();
			long overall_cost_i = env.getFullValidator().getNewSolutionCost();
			long overall_cost_r = env.getFullValidator()
					.getInitialSolutionCost();
			long overall_cost_b = best_solutions[i];
			double score = (overall_cost_i - overall_cost_b)
					/ (double) overall_cost_r;
			openAndAppendData(String
					.format("%s INITIAL_SOLUTION_COST=%,d NEW_COST=%,d (R=%d) BEST_COST=%,d ==> %.4f\n",
							datasets[i], overall_cost_r, overall_cost_i,
							mare2.getRounds(), overall_cost_b, score * 100));
			sum += score;
		}
		openAndAppendData(String.format("The cost is %.4f\n", sum * 100));
	}

	public void openAndAppendData(String aString) {
		try {
			FileWriter outFile = new FileWriter(fileName, true);
			BufferedWriter out = new BufferedWriter(outFile);
			out.write(aString);
			out.close();
		} catch (IOException ex) {
			ex.printStackTrace();
		}
	}
}
